package com.nowcoder.topic.hash.middle;

import java.util.HashMap;

/**
 * NC125 和为K的连续子数组
 * @author d3y1
 */
public class NC125 {
    /**
     * 代码中的类名、方法名、参数名已经指定，请勿修改，直接返回方法规定的值即可
     *
     * max length of the subarray sum = k
     * @param arr int整型一维数组 the array
     * @param k int整型 target
     * @return int整型
     */
    public int maxlenEqualK (int[] arr, int k) {
        // return solution1(arr, k);
        // return solution2(arr, k);
        // return solution3(arr, k);
        return solution33(arr, k);
    }

    /**
     * 枚举法: 超时!
     * @param arr
     * @param k
     * @return
     */
    private int solution1(int[] arr, int k){
        int n = arr.length;
        int result = 0;
        int sum;
        for(int j=0; j<n; j++){
            sum = 0;
            for(int i=j; i>=0; i--){
                sum += arr[i];
                if(sum == k){
                    result = Math.max(result, j-i+1);
                }
            }
        }

        return result;
    }

    /**
     * 前缀和: 超时!
     * @param arr
     * @param k
     * @return
     */
    private int solution2(int[] arr, int k){
        int n = arr.length;
        int[] pre = new int[n+1];
        for(int i=1; i<=n; i++){
            pre[i] = pre[i-1]+arr[i-1];
        }

        int sum;
        for(int gap=n; gap>0; gap--){
            for(int i=0,j=i+gap; j<=n; i++,j++){
                sum = pre[j]-pre[i];
                if(sum == k){
                    return j-i;
                }
            }
        }

        return 0;
    }

    /**
     * 前缀和 + 哈希
     * @param arr
     * @param k
     * @return
     */
    private int solution3(int[] arr, int k){
        int n = arr.length;
        int[] pre = new int[n+1];
        for(int i=1; i<=n; i++){
            pre[i] = pre[i-1]+arr[i-1];
        }

        int result = 0;
        HashMap<Integer,Integer> map = new HashMap<>();
        // sum=pre[j]-pre[i]=k => target=pre[i]=pre[j]-k
        int target;
        for(int j=0; j<=n; j++){
            target = pre[j]-k;
            if(map.containsKey(target)){
                result = Math.max(result, j-map.get(target));
            }
            // 记录最左边即可(题目求解最长连续子数组长度)
            if(!map.containsKey(pre[j])){
                // 表示: 前j个元素的和为pre[j]
                map.put(pre[j], j);
            }
        }

        return result;
    }

    /**
     * 前缀和 + 哈希
     *
     * 优化
     *
     * @param arr
     * @param k
     * @return
     */
    private int solution33(int[] arr, int k){
        int n = arr.length;
        int result = 0;
        HashMap<Integer,Integer> map = new HashMap<>();
        // sum=pre[j]-pre[i]=k => target=pre[i]=pre[j]-k
        int target,pre=0;
        // 表示: 前0个元素的和为pre(0)
        map.put(pre, 0);
        for(int j=1; j<=n; j++){
            pre += arr[j-1];
            target = pre-k;
            if(map.containsKey(target)){
                result = Math.max(result, j-map.get(target));
            }
            // 记录最左边即可(题目求解最长连续子数组长度)
            if(!map.containsKey(pre)){
                // 表示: 前j个元素的和为pre
                map.put(pre, j);
            }
        }

        return result;
    }
}